package com.leo.boot.jpa.search;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

import static com.leo.boot.jpa.search.Operator.*;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class ExpressionImpl implements Expression {

    static final Expression EMPTY = new ExpressionImpl(null, NP, null);

    private Object left;

    private Operator operator;

    private Object right;

    public static Expression of(Object left, Operator operator, Object right) {
        if (operator == null) {
            return EMPTY;
        }
        if (operator.isConditional()) {
            if (isNullOrEmpty(left) && isNullOrEmpty(right)) {
                return EMPTY;
            }
            if (isNullOrEmpty(left)) {
                return (Expression) right;
            }
            if (isNullOrEmpty(right)) {
                return (Expression) left;
            }
        } else {
            if (left == null || right == null) {
                return EMPTY;
            }
        }
        return new ExpressionImpl(left, operator, right);
    }

    private static boolean isNullOrEmpty(Object expression) {
        return !(expression instanceof Expression) || expression == EMPTY;
    }

    @Override
    public String toString() {
        return wrap(getLeft()) + getOperator().getOp() + wrap(getRight());
    }

    private String wrap(Object child) {
        if (isNullOrEmpty(child)) {
            return String.valueOf(child);
        }
        Expression childExpression = (Expression) child;
        if (getOperator() == Operator.AND && childExpression.getOperator() == Operator.OR) {
            return LP.getOp() + String.valueOf(child) + RP.getOp();
        } else {
            return String.valueOf(child);
        }
    }
}
